#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>

using namespace std;

#define TNUM 3                                                                            // 线程数量
typedef void (*func_t)(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond); // 函数指针

volatile bool quit = false;

class threadData
{
public:
    threadData(const string &name, func_t f, pthread_mutex_t *pmtx, pthread_cond_t *pcond) : tname(name), func(f), pmtx_(pmtx), pcond_(pcond) {}
    string tname;
    func_t func;
    pthread_mutex_t *pmtx_; // 互斥锁
    pthread_cond_t *pcond_; // 条件变量
};

void func1(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx); // 立刻阻塞，在该条件变量下等待被唤醒，同时释放抢到的锁
        cout << "fun 1 [" << pthread_self() << "]" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func2(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx); // 立刻阻塞，在该条件变量下排队等待被唤醒，同时释放抢到的锁
        cout << "fun 2 [" << pthread_self() << "]" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func3(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx); // 立刻阻塞，在该条件变量下等待被唤醒，同时释放抢到的锁
        cout << "fun 3 [" << pthread_self() << "]" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void *Entry(void *args)
{
    threadData *td = (threadData *)args;
    td->func(td->tname, td->pmtx_, td->pcond_); // 所有线程拿到同一把锁和同一个条件变量,并执行各自任务
    return (void *)td;
}

int main()
{
    pthread_mutex_t mtx; // 互斥锁
    pthread_cond_t cond; // 条件变量
    pthread_mutex_init(&mtx, NULL);
    pthread_cond_init(&cond, NULL); // 初始化

    pthread_t tid[TNUM];
    func_t funclist[TNUM] = {func1, func2, func3}; // 任务列表
    for (int i = 0; i < TNUM; i++)
    {
        threadData *td = new threadData("thread " + to_string(i + 1), funclist[i], &mtx, &cond); // 构建线程传参数据
        pthread_create(tid + i, NULL, Entry, (void *)td);
    }
    sleep(1);

    // 控制子线程
    int cnt = 0;
    while (cnt < 5)
    {
        pthread_cond_signal(&cond); // 唤醒一个在该条件变量下等待的线程
        sleep(1);                   // 每隔一秒唤醒一个

        // pthread_cond_broadcast(&cond); // 唤醒所有在该条件变量下等待的线程
        // sleep(3);                      // 每隔三秒唤醒一批
        cnt++;
    }
    cout << "ctrl done" << endl;
    quit = true;
    pthread_cond_broadcast(&cond);

    for (int i = 0; i < TNUM; i++)
    {
        threadData *td = NULL;
        pthread_join(tid[i], (void **)&td); // 等待线程退出
        cout << td->tname << " quit" << endl;
        delete td;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond); // 销毁

    // pthread_mutex_lock(&mtx); // 加锁
    // while (/*资源就绪*/)          // 检测临界资源就绪
    // {
    //     pthread_cond_wait(&cond, &mtx); // 等待被唤醒
    // }

    // // 访问临界资源

    // pthread_mutex_lock(&mtx); // 解锁

    return 0;
}
